import pygame
import math
import time
import random

# 游戏常量
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 600
GROUND_HEIGHT = 500
BALL_RADIUS = 8
GRAVITY = 980
AIR_FRICTION = 0.1
MAX_POWER = 800
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)

pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
font = pygame.font.Font(None, 24)


class ThrowRecord:
    def __init__(self, distance, duration):
        self.distance = distance
        self.duration = duration


class GameState:
    def __init__(self):
        self.reset()
        self.records = []

    def reset(self):
        self.angle = 45
        self.power = 300
        self.ball_pos = [50, GROUND_HEIGHT - BALL_RADIUS]
        self.ball_vel = [0, 0]
        self.flying = False
        self.dragging = False
        self.start_time = 0
        self.current_distance = 0
        self.current_time = 0


state = GameState()


def draw_ground():
    pygame.draw.line(screen, WHITE, (0, GROUND_HEIGHT),
                     (SCREEN_WIDTH, GROUND_HEIGHT), 2)


def draw_arrow(start, end):
    pygame.draw.line(screen, RED, start, end, 3)
    dx = end[0] - start[0]
    dy = end[1] - start[1]
    angle = math.atan2(dy, dx)
    arrow_size = 15
    points = [
        (end[0] - arrow_size * math.cos(angle - math.pi / 6),
         end[1] - arrow_size * math.sin(angle - math.pi / 6)),
        end,
        (end[0] - arrow_size * math.cos(angle + math.pi / 6),
         end[1] - arrow_size * math.sin(angle + math.pi / 6))
    ]
    pygame.draw.lines(screen, RED, False, points, 3)


def draw_ui():
    # 绘制状态信息
    angle_text = font.render(f"角度: {state.angle:.1f}°", True, WHITE)
    power_text = font.render(f"力量: {int(state.power)}N", True, WHITE)
    screen.blit(angle_text, (20, 20))
    screen.blit(power_text, (20, 50))

    # 绘制当前投掷信息
    if state.flying:
        time_text = font.render(f"飞行时间: {state.current_time:.2f}s", True, WHITE)
        dist_text = font.render(f"飞行距离: {state.current_distance:.2f}m", True, WHITE)
        screen.blit(time_text, (20, 100))
        screen.blit(dist_text, (20, 130))

    # 绘制排行榜
    rank_text = font.render("最佳记录 (Top 10):", True, WHITE)
    screen.blit(rank_text, (20, 200))
    for i, record in enumerate(state.records[:10]):
        record_text = font.render(
            f"{i + 1}. {record.distance:.2f}m ({record.duration:.2f}s)",
            True, WHITE)
        screen.blit(record_text, (20, 230 + i * 25))

    # 绘制重新开始按钮
    pygame.draw.rect(screen, WHITE, (SCREEN_WIDTH - 120, 20, 100, 40), 2)
    restart_text = font.render("重新开始", True, WHITE)
    screen.blit(restart_text, (SCREEN_WIDTH - 110, 30))

    # 绘制投掷箭头
    if not state.flying and not state.dragging:
        start = state.ball_pos
        radians = math.radians(state.angle)
        length = state.power / 8
        end = (
            start[0] + length * math.cos(radians),
            start[1] - length * math.sin(radians)
        )
        draw_arrow(start, end)


def update_physics(dt):
    if state.flying:
        state.ball_vel[1] += GRAVITY * dt
        state.ball_vel[0] *= math.exp(-AIR_FRICTION * dt)
        state.ball_vel[1] *= math.exp(-AIR_FRICTION * dt)
        state.ball_pos[0] += state.ball_vel[0] * dt
        state.ball_pos[1] += state.ball_vel[1] * dt

        if state.ball_pos[1] + BALL_RADIUS >= GROUND_HEIGHT:
            state.flying = False
            state.records.append(ThrowRecord(state.current_distance, state.current_time))
            state.records.sort(key=lambda x: -x.distance)
            state.ball_pos = [50, GROUND_HEIGHT - BALL_RADIUS]

        state.current_time = time.time() - state.start_time
        state.current_distance = (state.ball_pos[0] - 50) / 10


def handle_input():
    mouse_pos = pygame.mouse.get_pos()

    # 处理重新开始按钮点击
    if pygame.mouse.get_pressed()[0]:
        if SCREEN_WIDTH - 120 < mouse_pos[0] < SCREEN_WIDTH - 20 and 20 < mouse_pos[1] < 60:
            state.records = []
            state.reset()

    # 处理拖拽投掷
    if not state.flying:
        if pygame.mouse.get_pressed()[0]:
            dx = mouse_pos[0] - state.ball_pos[0]
            dy = state.ball_pos[1] - mouse_pos[1]
            distance = math.hypot(dx, dy)

            if distance < 50:  # 开始拖拽
                state.dragging = True

        if state.dragging:
            dx = mouse_pos[0] - state.ball_pos[0]
            dy = state.ball_pos[1] - mouse_pos[1]
            angle = math.degrees(math.atan2(dy, dx))
            state.angle = max(0, min(90, angle))
            state.power = min(math.hypot(dx, dy) * 2, MAX_POWER)

            # 实时绘制拖拽箭头
            start = state.ball_pos
            end = mouse_pos
            draw_arrow(start, end)

        if not pygame.mouse.get_pressed()[0] and state.dragging:
            state.dragging = False
            radians = math.radians(state.angle)
            state.ball_vel = [
                state.power * math.cos(radians),
                -state.power * math.sin(radians)
            ]
            state.flying = True
            state.start_time = time.time()


running = True
clock = pygame.time.Clock()
prev_time = time.time()

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    current_time = time.time()
    dt = current_time - prev_time
    prev_time = current_time

    handle_input()
    update_physics(dt)

    screen.fill(BLACK)
    draw_ground()
    pygame.draw.circle(screen, RED, [int(state.ball_pos[0]),
                                     int(state.ball_pos[1])], BALL_RADIUS)
    draw_ui()

    pygame.display.flip()
    clock.tick(60)

pygame.quit()